package com.oly.cms.admin.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.oly.cms.admin.mapper.CmsCategoryMapper;
import com.oly.cms.admin.service.ICmsCategoryService;
import com.oly.cms.common.constant.CmsCacheConstant;
import com.oly.cms.common.domain.VisibleParam;
import com.oly.cms.common.domain.entity.CmsCategory;
import com.oly.cms.common.domain.entity.CmsCategoryTheme;
import com.oly.cms.common.enums.CategoryNodeTypeEnums;
import com.oly.cms.common.enums.NodeTypeEnums;
import com.oly.cms.common.event.CacheWebRefreshAllEvent;
import com.oly.cms.common.model.properties.OlyCmsConfigProperties;
import com.oly.cms.query.mapper.CategorySearchMapper;
import com.oly.cms.query.model.param.CategorySearchParam;
import com.grace.common.constant.UserConstants;
import com.grace.common.exception.ServiceException;
import com.grace.common.utils.StringUtils;
import com.grace.system.service.impl.SysSearchConfigServiceImpl;

@Service
public class CmsCategoryServiceImpl implements ICmsCategoryService {

    @Autowired
    private CmsCategoryMapper categoryMapper;

    @Autowired
    private CategorySearchMapper categorySearchMapper;

    @Autowired
    private SysSearchConfigServiceImpl configService;

    @Autowired
    private ApplicationEventPublisher app;

    @Override
    public int insertCmsCategory(CategorySearchParam param) {
        if (!checkCategoryUnique(param, false)) {
            throw new ServiceException("请检查路径或分类名是否重复");
        } else if (param.getParentId() == 0) {
            param.setAncestors("0");
        } else {
            param.setCategoryId(param.getParentId());
            CmsCategory ca = categorySearchMapper.selectCmsCategoryById(param);
            if (ca == null || NodeTypeEnums.LEAF.ordinal() == CategoryNodeTypeEnums.valueOf(ca.getNodeType())
                    .getNodeTypeEnum().ordinal()) {
                throw new ServiceException("插入点不存在,或插入点非树干点");
            } else {
                param.setAncestors(ca.getAncestors() + "," + param.getParentId());
            }
        }
        int re = categoryMapper.insertCmsCategory(param);
        app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.CATEGORIES_CACHE_KEY_PREFIX));
        return re;
    }

    @Override
    @Transactional
    public int updateCmsCategory(CategorySearchParam param) {
        if (param.getCategoryId().longValue() == param.getParentId().longValue()) {
            throw new ServiceException("不能选择自己作为父节点");
        } else if (NodeTypeEnums.LEAF.ordinal() == CategoryNodeTypeEnums.valueOf(param.getNodeType()).getNodeTypeEnum()
                .ordinal()
                && !this.checkCategoryUnique(param, true)) {
            throw new ServiceException("存在子节点不允许修改节点类型");
        } else if (!checkCategoryUnique(param, false)) {
            throw new ServiceException("请检查路径或者分类名是否重复");
        } else if (param.getParentId().longValue() == 0) {
            param.setAncestors("0");
        } else {
            CategorySearchParam sp = new CategorySearchParam();
            sp.setCategoryId(param.getParentId());
            CmsCategory ca = categorySearchMapper.selectCmsCategoryById(sp);
            // 非目录不允许更新
            if (ca == null || NodeTypeEnums.LEAF.ordinal() == CategoryNodeTypeEnums.valueOf(ca.getNodeType())
                    .getNodeTypeEnum().ordinal()) {
                throw new ServiceException("更新点不存在或更新点叶子节点");
            } else {
                param.setAncestors(ca.getAncestors() + "," + param.getParentId());
            }
        }
        int c = categoryMapper.updateCmsCategory(param);
        // 同时更新子节点
        CmsCategory childCategory = new CmsCategory();
        childCategory.setParentId(param.getCategoryId());
        childCategory.setUpdateBy(param.getUpdateBy());
        childCategory.setAncestors(param.getAncestors() + "," + param.getCategoryId());
        updateChildNode(childCategory);
        updateChildCategoryVisible(param);
        app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.CATEGORIES_CACHE_KEY_PREFIX));
        return c;

    }
    
    
    @Override
    public int updateChildCategoryVisible(CmsCategory param) {
        int re = 0;
        if ("true".equals(configService.selectConfigDefaultValue(OlyCmsConfigProperties.CMS_CONFIG_GROUP.defaultValue(),
                OlyCmsConfigProperties.CATEGORY_UPDATE_CHILD))) {
            re = categoryMapper.updateChildCategoryVisible(param);
        }
        return re;
    }

    @Override
    public int deleteCmsCategoryById(Long catId) {
        CmsCategory param = new CmsCategory();
        param.setCategoryId(catId);
        if (!this.checkCategoryUnique(param, true)) {
            throw new ServiceException("存在子节点不允许删除");
        }
        CmsCategoryTheme cmsCategoryTheme = new CmsCategoryTheme();
        cmsCategoryTheme.setCategoryId(catId);
        if (!StringUtils.isEmpty(categoryMapper.listCategoryTheme(cmsCategoryTheme))) {
            throw new ServiceException("与主题有关联不允许删除");
        }
        if (categoryMapper.countArticleByCategoryId(catId) > 0) {
            throw new ServiceException("与文章有关联不允许删除");
        }
        int re = categoryMapper.deleteCmsCategoryById(catId);
        app.publishEvent(new CacheWebRefreshAllEvent(this, CmsCacheConstant.CATEGORIES_CACHE_KEY_PREFIX));
        return re;
    }

    @Override
    public List<CmsCategory> listCmsCategory(CategorySearchParam param) {
        return categorySearchMapper.listCmsCategory(param);
    }

    @Override
    public CmsCategory selectCmsCategoryById(CategorySearchParam param) {
        return categorySearchMapper.selectCmsCategoryById(param);
    }

    /**
     * 可用于验证
     * 分类名
     * 分类路径
     * 是否存在子节点
     * 
     */
    @Override
    public boolean checkCategoryUnique(CmsCategory param, boolean node) {
        CmsCategory gf = null;
        if (node) {
            gf = new CmsCategory();
            gf.setParentId(param.getCategoryId());
        } else {
            gf = param;
        }
        CmsCategory checkCat = categorySearchMapper.checkCategoryUnique(gf);
        if (checkCat == null || checkCat.getCategoryId()
                .longValue() == (param.getCategoryId() == null ? -1L : param.getCategoryId())) {
            return UserConstants.UNIQUE;
        } else {
            return UserConstants.NOT_UNIQUE;
        }

    }

    @Override
    public int countArticleByCategoryId(Long catId) {
        return categoryMapper.countArticleByCategoryId(catId);
    }

    @Override
    public List<CmsCategory> listCmsCategoryByArticleId(VisibleParam vParam) {
        return categorySearchMapper.listArticleCategoryByArticleId(vParam);
    }

    private void updateChildNode(CmsCategory param) {
        if (updateChildCatAncestors(param) > 0) {
            List<Long> childIds = selectChildIds(param.getParentId());
            if (childIds != null) {
                for (int i = 0; i < childIds.size(); i++) {
                    param.setParentId(childIds.get(i));
                    param.setAncestors(param.getAncestors() + "," + childIds.get(i));
                    updateChildNode(param);
                }
            }
        }
    }

    /**
     * 根据父亲Id修改Ancestors 根据父亲Id获取子元素子节点，循环遍历
     * 
     * @param parentId
     * @return
     */
    private List<Long> selectChildIds(long parentId) {
        return categoryMapper.listCategoryIdsByParentId(parentId);
    }

    private int updateChildCatAncestors(CmsCategory param) {
        return categoryMapper.updateChildCategoryAncestors(param);
    }

    @Override
    public int insertCategoryTheme(String themeName, List<Long> categoryIds) {
        for (Long categoryId : categoryIds) {
            categoryMapper.insertCategoryTheme(themeName, categoryId);
        }
        return categoryIds.size();

    }

    @Override
    public int deleteCategoryTheme(String themeName, List<Long> categoryIds) {
        for (Long categoryId : categoryIds) {
            categoryMapper.deleteCategoryTheme(themeName, categoryId);
        }
        return categoryIds.size();
    }

    @Override
    public List<CmsCategoryTheme> listCategoryTheme(CmsCategoryTheme categoryTheme) {

        return categoryMapper.listCategoryTheme(categoryTheme);
    }

}
